package com.googlecode.olabs.common.client.contact.formats.vcard;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.googlecode.olabs.common.client.Logger;
import com.googlecode.olabs.common.client.contact.Contact;
import com.googlecode.olabs.common.client.contact.ContactException;
import com.googlecode.olabs.common.client.contact.ContactImpl;
import com.googlecode.olabs.common.client.contact.field.Field;
import com.googlecode.olabs.common.client.contact.formats.AbstractParser;

public class VCardParser extends AbstractParser {

	public Contact parse(List<String> card) throws ContactException {
		if (card.size() <= 3) {
			return null;
		}
		int start = getNonEmptyIndex(card, true);
		int end = getNonEmptyIndex(card, false);
		if (start == -1 || end <= start + 1) {
			throw new ContactException("There's nothing in this card");
		}
		if (!card.get(start).toUpperCase().equals(VCardFormat.BEGIN_VCARD)) {
			throw new ContactException("Card must start with "
					+ VCardFormat.BEGIN_VCARD);
		}
		if (!card.get(start + 1).toUpperCase().equals(VCardFormat.VERSION_3_0)) {
			throw new ContactException("Card must have a "
					+ VCardFormat.VERSION_3_0 + " tag second");
		}
		if (!card.get(end).toUpperCase().equals(VCardFormat.END_VCARD)) {
			throw new ContactException("Card must end with "
					+ VCardFormat.END_VCARD);
		}

		return parse(card, start + 2, end - 1);
	}

	private int getNonEmptyIndex(List<String> strings, boolean startFromTop) {
		for (int i = 0; i < strings.size(); i++) {
			int index = i;
			if (!startFromTop) {
				index = strings.size() - 1 - i;
			}
			if (strings.get(index).trim().length() > 0) {
				return index;
			}
		}
		return -1;
	}

	private Contact parse(List<String> card, int startInclusive,
			int endExclusive) throws ContactException {
		Contact contact = new ContactImpl();
		for (int i = startInclusive; i <= endExclusive; i++) {
			contact.addField(parseLine(card.get(i)));
		}
		return contact;
	}

	private Field parseLine(String field) throws ContactException {
		final int splitPosition = field.indexOf(":");
		if (splitPosition == -1) {
			final String message = "Each line should have a : in it";
			Logger.get().debug(message + " - " + field);
			throw new ContactException(message);
		}
		String types = field.substring(0, splitPosition);
		String[] subTypes = types.split(";");
		List<String> subTypeList = parseOutSubTypes(subTypes);
		return super.createField(subTypes[0], subTypeList, Arrays.asList(field
				.substring(splitPosition + 1).split(";")));
	}

	private List<String> parseOutSubTypes(String[] subTypes) {
		List<String> result = new ArrayList<String>(subTypes.length - 1);
		for (int i = 1; i < subTypes.length; i++) {
			result.add(parseSubType(subTypes[i]));
		}
		return result;
	}

	private String parseSubType(String subType) {
		String[] split = subType.split("=");
		if (split.length == 1) {
			return subType.toUpperCase();
		} else {
			return split[1].toUpperCase();
		}
	}
}
